package model

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"goweb/ext/settings"
	"goweb/utils/commons"
	"goweb/utils/mysql"

	"github.com/json-iterator/go"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type User struct {
	/**
	Id  主键id
	Uid 用户id(64位)
	UserName用户名
	PassWord 密码
	Source 来源
	Role 角色
	*/
	Uid         string    `xorm:"pk notnull varchar(100) 'Uid'"`
	Utime       string    `xorm:"varchar(200) 'Utime'"`
	UserName    string    `xorm:"varchar(50) notnull unique 'UserName'"`
	NiceName    string    `xorm:"varchar(100) 'NiceName'"`
	Password    string    `xorm:"varchar(100) 'Password'"`
	Staf        int       `xorm:"int(4) 'Staf'"`                      //是否可以登录后台
	Status      int       `xorm:"int(4) not null default 0 'Status'"` //用户是否禁用
	CreatedTime time.Time `xorm:" created 'CreatedTime'"`
	UpdatedTime time.Time `xorm:" updated 'UpdatedTime'"`
}

type Source struct {
	SourceId string `xorm:" notnull varchar(100) 'SourceId'"` //sourceId是一级来源的MD5
	// 如果一级来源下面二级来源token公用，sourceid就是一级来源算,如果不共用token,就用二级来源算
	SourceName    string `xorm:"varchar(100) 'SourceName'"`  //来源名称
	SourceSecId   string `xorm:"varchar(100) 'SourceSecId'"` //表示是一个大类的相同来源(eg:天猫淘宝)
	SourceSecName string `xorm:"varchar(100) 'SourceSecName'"`
	Flag          int    `xorm:"int(11) 'Flag'"` // 标记(是否踢出)
}

type UserSource struct {
	Id       int64
	Uid      string `xorm:"pk notnull varchar(100) 'Uid'"`
	SourceId string `xorm:"varchar(100) 'SourceId'"`
}

type Role struct {
	Id     int64
	RoleId string `xorm:"int(11) 'RoleId'"`
	Name   string `xorm:"varchar(100) 'Name'"`                 //描述
	Status int    `xorm:"int(11) not null default 0 'Status'"` //标记角色是否被禁用 0 不禁用 ,1 禁用
}

type Permission struct {
	//PerId string `xorm:"pk autoincr notnull int(11) 'PerId'"`
	PerId string `xorm:"pk  notnull int(11) 'PerId'"`
	Name  string `xorm:"varchar(100) 'Name'"`
	Url   string `xorm:"varchar(250) 'Url'"`
}

type UserPer struct {
	Id     int64
	Uid    string `xorm:"varchar(100) 'Uid'"`
	PerId  string `xorm:"varchar(6) 'PerId'"`
	Status int    `xorm:"int(11) not null default 0 'Status'"` //标记角色是否被禁用 0 不禁用 ,1 禁用
}

type UserRole struct {
	Id     int64
	Uid    string `xorm:"varchar(100) 'Uid'"`
	RoleId string `xorm:"varchar(4) 'RoleId'"`
}

type RolePer struct {
	Id     int64
	RoleId string `xorm:"varchar(100) 'RoleId'"`
	PerId  string `xorm:"varchar(100) 'PerId'"` //权限id
}

/**
验证用户登录信息
*/
func Auth(username, password, sourceId string) (int, string, string, string, bool) {
	sql := fmt.Sprintf("SELECT DISTINCT u.Uid,u.uTime,us.SourceId,s.Flag, u.Staf FROM  user_source us,`user` u,`source` s WHERE s.SourceId=us.SourceId AND u.UserName='%s' "+
		"AND u.Password = '%s' AND us.SourceId= '%s'", username, password, sourceId)
	query, err := conf.MasterDB.QueryString(sql)
	atoi := 0

	if len(query) < 1 {
		return atoi, conf.STRING_FLAG, "", "", false
	}
	if commons.CheckErr(err) {
		atoi, _ = strconv.Atoi(query[0]["Staf"])
		//这里只把SourceId和token返回去组合成一个
		//sourceId  firstId + flag 构成
		//页面添加用户的时候可以选择是否公用token
		//staf, sourceId, uid, uTime, flag
		return atoi, query[0]["SourceId"], query[0]["Uid"], query[0]["uTime"], true
	}

	return atoi, conf.STRING_FLAG, "", "", false
}

/**
用过uid获取用户信息
*/
func CheckAuth(uid string) (string, string, bool) {
	user := new(User)
	byUid := ExistUserSourceByUid(uid)
	if byUid == conf.STRING_FLAG {
		return conf.STRING_FLAG, "", false
	}

	has, err := conf.MasterDB.Where("Uid=? ", uid).Get(user)

	if err != nil {
		conf.Logger.Info("has", has, err)
		return conf.STRING_FLAG, "", false
	}

	return byUid, user.Utime, false
}

/**
检查权限,角色可以禁用,用户角色也可以禁用(2中不同的模式)
获取用户权限

有bug，不能设置到redis，启动的时候设置
*/

func GetUserPer(uid string) (bool, []map[string]string) {
	sql := fmt.Sprintf("SELECT u.uid, p.perId, p.url FROM `user` u, `user_role` ur, `role` r, `role_per` rp, "+
		"`permission` p WHERE u.uid = ur.uid AND ur.roleId = r.`roleId`  AND ur.roleId = rp.`roleId`  AND "+
		"rp.`perId` = p.`perId`   AND r.`status` = 0 AND   u.`uid` = '%s' "+
		"UNION SELECT  u.uid, p.perId, p.url FROM `user` u, `user_per` up, `permission` p WHERE "+
		"u.uid = up.`uid` AND up.`perId` = p.`perId`  and up.`status` = 0 and u.`uid` = '%s';", uid, uid)
	query, err := conf.MasterDB.QueryString(sql)
	if commons.CheckErr(err) {
		return true, query
	}

	return false, nil
}

func GetAllPer() (per []Permission, b bool) {

	find := conf.MasterDB.Find(&per)
	if commons.CheckErr(find) {
		return per, true
	}

	return nil, false

}

func ExistRoleByID(value string) bool {
	get, err := conf.MasterDB.Where("roleId=? ", value).Exist(&Role{})

	if err != nil {
		conf.Logger.Info("ExistUser:", err)
	}
	return get

}

/**
返回false表示角色存在
*/
func AddRole(roleId, name string) bool {
	role := Role{RoleId: roleId, Name: name}
	_, err := conf.MasterDB.Insert(role)

	if commons.CheckErr(err) {
		return true
	}

	return false

}

func ExistUserSourceByUid(uid string) string {
	userSource := new(UserSource)
	_, err := conf.MasterDB.Where("Uid=?", uid).Get(userSource)

	if err != nil {
		conf.Logger.Info("ExistUser:", err)
		return conf.STRING_FLAG
	}
	return userSource.SourceId
}

/**
添加用户
*/
func AddUser(username, password, sourceId string) bool {
	uid := commons.EncodeMd5(username + password + sourceId + conf.JwtBase.JwtSecret)
	uTime := commons.EncodeMd5(time.Now().String() + username[:5] + "_+%XHC")
	auth := User{UserName: username, Password: password, Uid: uid, Utime: uTime}
	role := UserRole{Uid: uid, RoleId: "1"}
	rolePer := RolePer{RoleId: "1", PerId: "1"}
	userSource := UserSource{Uid: uid, SourceId: sourceId}

	if ExistUserSourceByUid(uid) == conf.STRING_FLAG {
		//表示用户名已经存在
		return false
	}

	sess := conf.MasterDB.NewSession()

	var err error
	if err = sess.Begin(); err != nil {
		return false
	}
	defer sess.Rollback()
	if !(mysql.CheckErrInsert(sess, auth) && mysql.CheckErrInsert(sess, role) &&
		mysql.CheckErrInsert(sess, rolePer) && mysql.CheckErrInsert(sess, userSource)) {
		return false
	}
	sess.Commit()
	sess.Close()
	return true

}

func UpdateUser(uid string, data map[string]interface{}) bool {
	update, _ := conf.MasterDB.Table(new(User)).Where("uid=? ", uid).Update(data)

	if update >= 1 {
		return true
	} else {
		return false
	}

}

/**
修改用户权限
1:用户uid
2:用户权限
3:给的权限id{获取所有权限列表}

role user_role user_per role_per per
*/

func UpdateUserPer(roleId, name, uid, perId, url string) bool {
	if ExistUserSourceByUid(uid) == conf.STRING_FLAG {
		//用户不存在
		return false
	}
	role := Role{RoleId: roleId, Name: name, Status: 0}
	userRole := UserRole{Uid: uid, RoleId: roleId}
	rolePer := RolePer{RoleId: roleId, PerId: perId}
	per := Permission{PerId: perId, Url: url}
	userPer := UserPer{Uid: uid, PerId: perId, Status: 0}
	sess := conf.MasterDB.NewSession()

	var err error
	if err = sess.Begin(); err != nil {
		return false
	}

	if !(mysql.CheckErrInsert(sess, role) && mysql.CheckErrInsert(sess, userRole) && mysql.CheckErrInsert(sess, rolePer) &&
		mysql.CheckErrInsert(sess, per) && mysql.CheckErrInsert(sess, userPer)) {
		return false
	}
	sess.Commit()
	sess.Close()
	return true
}

func GetAllSourceM() []string {

	source := []Source{}

	find := conf.MasterDB.Find(&source)
	m := map[string][]string{}
	if commons.CheckErr(find) {
		for _, v := range source {
			m[v.SourceName] = append(m[v.SourceName], v.SourceSecName)
		}
	}

	arrData := []string{}
	data := make(map[string]interface{})
	for k, v := range m {
		fmt.Println(k, v)
		data["SourceName"] = k
		data["SourceSecName"] = v
		marshal, err := json.Marshal(data)
		if commons.CheckErr(err) {
			arrData = append(arrData, strings.Replace(string(marshal), "\\", "", -1))
		}
	}

	//strings := map[string]string{}
	return arrData
}

func AddSource() {

}

func InitPer() ([]Permission, error) {
	per := []Permission{}
	find := conf.MasterDB.Find(&per)
	//if commons.CheckErr(find) {
	//	for _, v := range per {
	//		redis.SetValue(v.Url, v.PerId, 60*60*24*30*36, conf.RDb0)
	//		redis.SetValue(v.PerId, v.Url, 60*60*24*30*36, conf.RDb3)
	//	}
	//}

	return per, find

}

func GetAllUserPer() ([]map[string]string, error) {
	sql := "SELECT u.Uid, p.PerId FROM `user` u, `user_role` ur, `role` r, `role_per` rp, `permission` p " +
		"WHERE u.Uid = ur.Uid AND ur.RoleId = r.RoleId AND ur.RoleId = rp.RoleId AND rp.PerId = p.PerId  AND " +
		"r.Status = 0 UNION SELECT u.uid, p.perId FROM `user` u, `user_per` up, `permission` p WHERE u.Uid " +
		"= up.Uid AND up.PerId = p.PerId and up.Status = 0"
	strings, err := conf.MasterDB.QueryString(sql)
	//if commons.CheckErr(err) {
	//	fmt.Println(strings)
	//	for k, v := range strings {
	//		fmt.Println("allUserPer", k, v["Uid"], v)
	//		marshal, _ := json.Marshal(&v)
	//		redis.SetValue(conf.PERX_PER+v["Uid"], string(marshal), 60*60*24*30*36, conf.RDb2)
	//
	//	}
	//}
	return strings, err

}
